#include "./BSP/LCD/lcd.h"
#include "./BSP/LCD/lcd_init.h"
#include "./BSP/LCD/lcdfont.h"
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

/* -------------------------------------------- 全局变量定义 -------------------------------------------- */

/* LCD的画笔颜色和背景色 */
uint32_t g_point_color = WHITE;     /* 画笔颜色 */
uint32_t g_back_color  = BLACK;     /* 背景色 */

/* -------------------------------------------- 基础绘图函数 -------------------------------------------- */

/**
 * @brief LCD清屏函数
 * @param 无
 * @return 无
 * @details 使用背景色清空整个LCD显示区域
 */
void LCD_Clear(void)
{
    LCD_Fill(0, 0, LCD_W, LCD_H, g_back_color);
}

/**
 * @brief LCD反色显示控制函数
 * @param invert 反色显示控制参数，1开启反色，0关闭反色
 * @return 无
 * @details 通过设置LCD的INVON/INVOFF命令来控制显示反色
 */
void LCD_DisplayInvertColor(uint8_t invert)
{
    LCD_WR_REG(invert ? 0x21 /* INVON */ : 0x20 /* INVOFF */);  /* 根据参数控制反色显示 */
}

/**
 * @brief 在指定区域填充颜色
 * @param xsta 区域起始点x坐标(0~LCD_W)
 * @param ysta 区域起始点y坐标(0~LCD_H)
 * @param xend 区域终止点x坐标(0~LCD_W)
 * @param yend 区域终止点y坐标(0~LCD_H)
 * @param color 要填充的16位RGB颜色值
 * @return 无
 * @details 通过设置显示区域，然后连续写入指定颜色数据来实现区域填充
 */
void LCD_Fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color)
{
    uint16_t i, j;
    LCD_Address_Set(xsta, ysta, xend - 1, yend - 1); /* 设置显示范围 */
    for (i = ysta; i < yend; i++)
    {
        for (j = xsta; j < xend; j++)
        {
            LCD_WR_DATA(color);
        }
    }
}

/**
 * @brief 在指定位置画点
 * @param x 点的x坐标(0~LCD_W)
 * @param y 点的y坐标(0~LCD_H)
 * @param color 点的16位RGB颜色值
 * @return 无
 * @details 通过设置点的显示位置，然后写入颜色数据来绘制单个像素点
 */
void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color)
{
    LCD_Address_Set(x, y, x, y); /* 设置光标位置 */
    LCD_WR_DATA(color);
}

/**
 * @brief 画线
 * @param x1 线段起始点x坐标(0~LCD_W)
 * @param y1 线段起始点y坐标(0~LCD_H)
 * @param x2 线段终止点x坐标(0~LCD_W)
 * @param y2 线段终止点y坐标(0~LCD_H)
 * @param color 线段的16位RGB颜色值
 * @return 无
 * @details 使用Bresenham算法绘制任意两点之间的直线
 */
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
    uint16_t t;
    int xerr = 0, yerr = 0, delta_x, delta_y, distance;
    int incx, incy, uRow, uCol;
    
    /* 计算坐标增量 */
    delta_x = x2 - x1;
    delta_y = y2 - y1;
    uRow = x1;              /* 画线起点坐标 */
    uCol = y1;
    
    /* 确定X方向步进值 */
    if (delta_x > 0)
        incx = 1;           /* 向右步进 */
    else if (delta_x == 0)
        incx = 0;           /* 垂直线，X方向不步进 */
    else
    {
        incx = -1;          /* 向左步进 */
        delta_x = -delta_x; /* 取绝对值 */
    }
    
    /* 确定Y方向步进值 */
    if (delta_y > 0)
        incy = 1;           /* 向下步进 */
    else if (delta_y == 0)
        incy = 0;           /* 水平线，Y方向不步进 */
    else
    {
        incy = -1;          /* 向上步进 */
        delta_y = -delta_y; /* 取绝对值 */
    }
    
    /* 选取基本增量坐标轴（取较大值） */
    if (delta_x > delta_y)
        distance = delta_x;
    else
        distance = delta_y;
    
    /* Bresenham算法绘制直线 */
    for (t = 0; t < distance + 1; t++)
    {
        LCD_DrawPoint(uRow, uCol, color); /* 绘制当前点 */
        xerr += delta_x;    /* 累加X方向误差 */
        yerr += delta_y;    /* 累加Y方向误差 */
        
        /* X方向误差达到阈值，X坐标步进 */
        if (xerr > distance)
        {
            xerr -= distance;
            uRow += incx;
        }
        
        /* Y方向误差达到阈值，Y坐标步进 */
        if (yerr > distance)
        {
            yerr -= distance;
            uCol += incy;
        }
    }
}

/**
 * @brief 画矩形
 * @param x1 矩形左上角x坐标(0~LCD_W)
 * @param y1 矩形左上角y坐标(0~LCD_H)
 * @param x2 矩形右下角x坐标(0~LCD_W)
 * @param y2 矩形右下角y坐标(0~LCD_H)
 * @param color 矩形边框的16位RGB颜色值
 * @return 无
 * @details 通过绘制四条直线形成矩形边框
 */
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
    LCD_DrawLine(x1, y1, x2, y1, color);
    LCD_DrawLine(x1, y1, x1, y2, color);
    LCD_DrawLine(x1, y2, x2, y2, color);
    LCD_DrawLine(x2, y1, x2, y2, color);
}

/**
 * @brief 画圆
 * @param x0 圆心x坐标(0~LCD_W)
 * @param y0 圆心y坐标(0~LCD_H)
 * @param r 圆的半径(像素点数)
 * @param color 圆边框的16位RGB颜色值
 * @return 无
 * @details 使用Bresenham算法绘制圆形边框
 */
void Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color)
{
    int a, b;
    a = 0;
    b = r;
    
    /* 使用Bresenham算法绘制圆的八个对称点 */
    while (a <= b)
    {
        /* 绘制圆的八个对称点（按顺时针方向） */
        LCD_DrawPoint(x0 - b, y0 - a, color); /* 3点钟方向 */
        LCD_DrawPoint(x0 + b, y0 - a, color); /* 0点钟方向 */
        LCD_DrawPoint(x0 - a, y0 + b, color); /* 1点钟方向 */
        LCD_DrawPoint(x0 - a, y0 - b, color); /* 2点钟方向 */
        LCD_DrawPoint(x0 + b, y0 + a, color); /* 4点钟方向 */
        LCD_DrawPoint(x0 + a, y0 - b, color); /* 5点钟方向 */
        LCD_DrawPoint(x0 + a, y0 + b, color); /* 6点钟方向 */
        LCD_DrawPoint(x0 - b, y0 + a, color); /* 7点钟方向 */
        
        a++; /* X坐标递增 */
        
        /* 判断当前点是否超出圆的半径范围 */
        if ((a * a + b * b) > (r * r))
        {
            b--; /* Y坐标递减 */
        }
    }
}

/* -------------------------------------------- 中文字符显示函数 -------------------------------------------- */

/**
 * @brief 显示汉字串
 * @param x 起始显示点x坐标(0~LCD_W)
 * @param y 起始显示点y坐标(0~LCD_H)
 * @param s 要显示的汉字字符串指针
 * @param fc 字体的16位RGB前景色
 * @param bc 字体的16位RGB背景色
 * @param sizey 字号大小(可选12/16/24/32像素)
 * @param mode 显示模式(0:非叠加模式，1:叠加模式)
 * @return 无
 * @details 在指定位置显示一串汉字，支持多种字号大小
 */
void LCD_ShowChinese(uint16_t x, uint16_t y, uint8_t *s, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint16_t x0 = x;                        /* 保存初始X坐标 */
    uint8_t CharLength = 0;                 /* 当前字符的字节长度 */
    
    while (*s != 0)
    {
        /* 计算当前字符的字节长度 */
#ifdef LCD_CHARSET_UTF8
        if ((*s & 0x80) == 0x00)            /* ASCII字符 */
        {
            CharLength = 1;
        }
        else if ((*s & 0xE0) == 0xC0)       /* 2字节UTF8字符 */
        {
            CharLength = 2;
        }
        else if ((*s & 0xF0) == 0xE0)       /* 3字节UTF8字符 */
        {
            CharLength = 3;
        }
        else if ((*s & 0xF8) == 0xF0)       /* 4字节UTF8字符 */
        {
            CharLength = 4;
        }
        else
        {
            CharLength = 1;                  /* 默认处理 */
        }
#else
        if ((*s & 0x80) == 0x00)            /* ASCII字符 */
        {
            CharLength = 1;
        }
        else                                /* 中文字符 */
        {
            CharLength = 2;
        }
#endif
        
        /* 根据字符类型选择显示方式 */
        if (CharLength == 1)                /* ASCII字符 */
        {
            LCD_ShowChar(x0, y, *s, fc, bc, sizey, mode);
            x0 += sizey / 2;                /* ASCII字符宽度为字号的一半 */
        }
        else                                /* 中文字符 */
        {
            if (sizey == 12)
                LCD_ShowChinese12x12(x0, y, s, fc, bc, sizey, mode);
            else if (sizey == 16)
                LCD_ShowChinese16x16(x0, y, s, fc, bc, sizey, mode);
            else if (sizey == 24)
                LCD_ShowChinese24x24(x0, y, s, fc, bc, sizey, mode);
            else if (sizey == 32)
                LCD_ShowChinese32x32(x0, y, s, fc, bc, sizey, mode);
            else
                return;
            x0 += sizey;                    /* 中文字符宽度等于字号 */
        }
        
        /* 移动指针到下一个字符 */
        s += CharLength;
    }
}

/**
 * @brief 显示单个12x12汉字
 * @param x x坐标
 * @param y y坐标
 * @param s 要显示的汉字
 * @param fc 字的颜色
 * @param bc 字的背景色
 * @param sizey 字号
 * @param mode 0非叠加模式，1叠加模式
 * @return 无
 */
void LCD_ShowChinese12x12(uint16_t x, uint16_t y, uint8_t *s, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint8_t i, j, m = 0;                  /* i:字节计数器，j:位计数器，m:像素计数器 */
    uint16_t k;                           /* k:字模库索引计数器 */
    uint16_t HZnum;                       /* 汉字数目：字模库中汉字的个数 */
    uint16_t TypefaceNum;                 /* 一个字符所占字节大小：字模数据的总字节数 */
    uint16_t x0 = x;                      /* 保存初始X坐标，用于叠加模式下的坐标重置 */
    
    /* 计算字模数据的总字节数 */
    /* sizey / 8：计算需要多少个字节来存储一行的数据 */
    /* (sizey % 8) ? 1 : 0：如果sizey不能被8整除，则需要额外一个字节 */
    /* 乘以sizey：因为总共有sizey行，所以总字节数 = 每行字节数 × 行数 */
    TypefaceNum = (sizey / 8 + ((sizey % 8) ? 1 : 0)) * sizey;

    /* 统计字模库中汉字的个数：总数组大小除以单个汉字结构体大小 */
    HZnum = sizeof(tfont12) / sizeof(typFNT_12x12);
    
    /* 遍历字模库，查找匹配的汉字 */
    for (k = 0; k < HZnum; k++)
    {
#ifdef LCD_CHARSET_UTF8     /* 定义字符集为UTF8 */
        /* 使用strcmp函数进行字符串比较，支持UTF8字符 */
        /* 比较字模库中的索引字符串和要显示的字符是否相同 */
        if (strcmp(tfont12[k].Index, (char *)s) == 0)
#endif
        
#ifdef LCD_CHARSET_GB2312   /* 定义字符集为GB2312 */
        /* 使用字节比较，支持GB2312字符 */
        /* 比较字模库中的两个字节索引和要显示的字符的两个字节是否相同 */
        if ((tfont12[k].Index[0] == *(s)) && (tfont12[k].Index[1] == *(s + 1)))
#endif
        {
            /* 设置LCD显示区域：从(x,y)到(x+sizey-1,y+sizey-1) */
            /* 这样LCD就知道要在这个正方形区域内显示汉字 */
            LCD_Address_Set(x, y, x + sizey - 1, y + sizey - 1);
            
            /* 逐字节处理字模数据 */
            for (i = 0; i < TypefaceNum; i++)
            {
                /* 逐位处理每个字节（每个字节8位，对应8个像素） */
                for (j = 0; j < 8; j++)
                {
                    if (!mode) /* 非叠加方式显示：直接写入LCD显存 */
                    {
                        /* 检查当前位是否为1（即是否需要显示像素） */
                        /* tfont12[k].Msk[i] & (0x01 << j)：提取第j位的值 */
                        if (tfont12[k].Msk[i] & (0x01 << j))
                            LCD_WR_DATA(fc);    /* 如果位为1，显示前景色 */
                        else
                            LCD_WR_DATA(bc);    /* 如果位为0，显示背景色 */
                        
                        m++;                    /* 像素计数器加1 */
                        if (m % sizey == 0)     /* 如果处理完一行（sizey个像素） */
                        {
                            m = 0;              /* 重置像素计数器 */
                            break;              /* 跳出内层循环，处理下一个字节 */
                        }
                    }
                    else /* 叠加方式显示：在现有内容上叠加显示 */
                    {
                        /* 检查当前位是否为1（即是否需要显示像素） */
                        if (tfont12[k].Msk[i] & (0x01 << j))
                            LCD_DrawPoint(x, y, fc); /* 在指定位置绘制一个前景色点 */
                        
                        x++;                    /* X坐标向右移动一个像素 */
                        if ((x - x0) == sizey)  /* 如果处理完一行（X坐标回到起始位置） */
                        {
                            x = x0;             /* 重置X坐标到起始位置 */
                            y++;                /* Y坐标向下移动一行 */
                            break;              /* 跳出内层循环，处理下一个字节 */
                        }
                    }
                }
            }
            return; /* 查找到对应点阵字库立即退出，防止多个汉字重复取模带来影响 */
        }
    }
    
    /* 如果没有找到对应的字符，显示问号作为错误提示 */
    LCD_ShowChar(x, y, '?', fc, bc, sizey, mode);
}

/**
 * @brief 显示单个16x16汉字
 * @param x x坐标
 * @param y y坐标
 * @param s 要显示的汉字
 * @param fc 字的颜色
 * @param bc 字的背景色
 * @param sizey 字号
 * @param mode 0非叠加模式，1叠加模式
 * @return 无
 */
void LCD_ShowChinese16x16(uint16_t x, uint16_t y, uint8_t *s, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint8_t i, j, m = 0;
    uint16_t k;
    uint16_t HZnum;       /* 汉字数目 */
    uint16_t TypefaceNum; /* 一个字符所占字节大小 */
    uint16_t x0 = x;
    TypefaceNum = (sizey / 8 + ((sizey % 8) ? 1 : 0)) * sizey;
    HZnum = sizeof(tfont16) / sizeof(typFNT_16x16); /* 统计汉字数目 */
    
    for (k = 0; k < HZnum; k++)
    {
#ifdef LCD_CHARSET_UTF8     /* 定义字符集为UTF8 */
        /* 使用strcmp函数进行字符串比较，支持UTF8字符 */
        if (strcmp(tfont16[k].Index, (char *)s) == 0)
#endif
        
#ifdef LCD_CHARSET_GB2312   /* 定义字符集为GB2312 */
        /* 使用字节比较，支持GB2312字符 */
        if ((tfont16[k].Index[0] == *(s)) && (tfont16[k].Index[1] == *(s + 1)))
#endif
        {
            LCD_Address_Set(x, y, x + sizey - 1, y + sizey - 1);
            for (i = 0; i < TypefaceNum; i++)
            {
                for (j = 0; j < 8; j++)
                {
                    if (!mode) /* 非叠加方式显示 */
                    {
                        if (tfont16[k].Msk[i] & (0x01 << j))
                            LCD_WR_DATA(fc);
                        else
                            LCD_WR_DATA(bc);
                        m++;
                        if (m % sizey == 0)
                        {
                            m = 0;
                            break;
                        }
                    }
                    else /* 叠加方式显示 */
                    {
                        if (tfont16[k].Msk[i] & (0x01 << j))
                            LCD_DrawPoint(x, y, fc); /* 在指定位置绘制一个点 */
                        x++;
                        if ((x - x0) == sizey)
                        {
                            x = x0;
                            y++;
                            break;
                        }
                    }
                }
            }
            return; /* 查找到对应点阵字库立即退出，防止多个汉字重复取模带来影响 */
        }
    }
    
    /* 如果没有找到对应的字符，显示问号作为错误提示 */
    LCD_ShowChar(x, y, '?', fc, bc, sizey, mode);
}

/**
 * @brief 显示单个24x24汉字
 * @param x x坐标
 * @param y y坐标
 * @param s 要显示的汉字
 * @param fc 字的颜色
 * @param bc 字的背景色
 * @param sizey 字号
 * @param mode 0非叠加模式，1叠加模式
 * @return 无
 */
void LCD_ShowChinese24x24(uint16_t x, uint16_t y, uint8_t *s, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint8_t i, j, m = 0;
    uint16_t k;
    uint16_t HZnum;       /* 汉字数目 */
    uint16_t TypefaceNum; /* 一个字符所占字节大小 */
    uint16_t x0 = x;
    TypefaceNum = (sizey / 8 + ((sizey % 8) ? 1 : 0)) * sizey;
    HZnum = sizeof(tfont24) / sizeof(typFNT_24x24); /* 统计汉字数目 */
    for (k = 0; k < HZnum; k++)
    {
#ifdef LCD_CHARSET_UTF8     /* 定义字符集为UTF8 */
        /* 使用strcmp函数进行字符串比较，支持UTF8字符 */
        if (strcmp(tfont24[k].Index, (char *)s) == 0)
#endif
        
#ifdef LCD_CHARSET_GB2312   /* 定义字符集为GB2312 */
        /* 使用字节比较，支持GB2312字符 */
        if ((tfont24[k].Index[0] == *(s)) && (tfont24[k].Index[1] == *(s + 1)))
#endif
        {
            LCD_Address_Set(x, y, x + sizey - 1, y + sizey - 1);
            for (i = 0; i < TypefaceNum; i++)
            {
                for (j = 0; j < 8; j++)
                {
                    if (!mode) /* 非叠加方式显示 */
                    {
                        if (tfont24[k].Msk[i] & (0x01 << j))
                            LCD_WR_DATA(fc);
                        else
                            LCD_WR_DATA(bc);
                        m++;
                        if (m % sizey == 0)
                        {
                            m = 0;
                            break;
                        }
                    }
                    else /* 叠加方式显示 */
                    {
                        if (tfont24[k].Msk[i] & (0x01 << j))
                            LCD_DrawPoint(x, y, fc); /* 在指定位置绘制一个点 */
                        x++;
                        if ((x - x0) == sizey)
                        {
                            x = x0;
                            y++;
                            break;
                        }
                    }
                }
            }
            return; /* 查找到对应点阵字库立即退出，防止多个汉字重复取模带来影响 */
        }
    }
    
    /* 如果没有找到对应的字符，显示问号作为错误提示 */
    LCD_ShowChar(x, y, '?', fc, bc, sizey, mode);
}

/**
 * @brief 显示单个32x32汉字
 * @param x x坐标
 * @param y y坐标
 * @param s 要显示的汉字
 * @param fc 字的颜色
 * @param bc 字的背景色
 * @param sizey 字号
 * @param mode 0非叠加模式，1叠加模式
 * @return 无
 */
void LCD_ShowChinese32x32(uint16_t x, uint16_t y, uint8_t *s, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint8_t i, j, m = 0;
    uint16_t k;
    uint16_t HZnum;         /* 汉字数目 */
    uint16_t TypefaceNum;   /* 一个字符所占字节大小 */
    uint16_t x0 = x;
    TypefaceNum = (sizey / 8 + ((sizey % 8) ? 1 : 0)) * sizey;
    HZnum = sizeof(tfont32) / sizeof(typFNT_32x32); /* 统计汉字数目 */
    for (k = 0; k < HZnum; k++)
    {
#ifdef LCD_CHARSET_UTF8     /* 定义字符集为UTF8 */
        /* 使用strcmp函数进行字符串比较，支持UTF8字符 */
        if (strcmp(tfont32[k].Index, (char *)s) == 0)
#endif
        
#ifdef LCD_CHARSET_GB2312   /* 定义字符集为GB2312 */
        /* 使用字节比较，支持GB2312字符 */
        if ((tfont32[k].Index[0] == *(s)) && (tfont32[k].Index[1] == *(s + 1)))
#endif
        {
            LCD_Address_Set(x, y, x + sizey - 1, y + sizey - 1);
            for (i = 0; i < TypefaceNum; i++)
            {
                for (j = 0; j < 8; j++)
                {
                    if (!mode) /* 非叠加方式显示 */
                    {
                        if (tfont32[k].Msk[i] & (0x01 << j))
                            LCD_WR_DATA(fc);
                        else
                            LCD_WR_DATA(bc);
                        m++;
                        if (m % sizey == 0)
                        {
                            m = 0;
                            break;
                        }
                    }
                    else /* 叠加方式显示 */
                    {
                        if (tfont32[k].Msk[i] & (0x01 << j))
                            LCD_DrawPoint(x, y, fc); /* 在指定位置绘制一个点 */
                        x++;
                        if ((x - x0) == sizey)
                        {
                            x = x0;
                            y++;
                            break;
                        }
                    }
                }
            }
            return; /* 查找到对应点阵字库立即退出，防止多个汉字重复取模带来影响 */
        }
    }
    
    /* 如果没有找到对应的字符，显示问号作为错误提示 */
    LCD_ShowChar(x, y, '?', fc, bc, sizey, mode);
}

/* -------------------------------------------- 字符和字符串显示函数 -------------------------------------------- */

/**
 * @brief 显示单个字符
 * @param x 字符显示位置x坐标(0~LCD_W)
 * @param y 字符显示位置y坐标(0~LCD_H)
 * @param num ASCII字符(0x20~0x7E)
 * @param fc 字符的16位RGB前景色
 * @param bc 字符的16位RGB背景色
 * @param sizey 字号大小(可选12/16/24/32/64像素)
 * @param mode 显示模式(0:非叠加模式，1:叠加模式)
 * @return 无
 * @details 在指定位置显示一个ASCII字符，支持多种字号大小
 */
void LCD_ShowChar(uint16_t x, uint16_t y, uint8_t num, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint8_t temp, sizex, t, m = 0;
    uint16_t i, TypefaceNum; /* 一个字符所占字节大小 */
    uint16_t x0 = x;
    sizex = sizey / 2;
    TypefaceNum = (sizex / 8 + ((sizex % 8) ? 1 : 0)) * sizey;
    num = num - ' ';                                     /* 得到字符在字库中的偏移值 */
    LCD_Address_Set(x, y, x + sizex - 1, y + sizey - 1); /* 设置字符显示区域 */
    for (i = 0; i < TypefaceNum; i++)
    {
        if (sizey == 12)
            temp = ascii_1206[num][i]; /* 调用6x12字体 */
        else if (sizey == 16)
            temp = ascii_1608[num][i]; /* 调用8x16字体 */
        else if (sizey == 24)
            temp = ascii_2412[num][i]; /* 调用12x24字体 */
        else if (sizey == 32)
            temp = ascii_3216[num][i]; /* 调用16x32字体 */
        else if (sizey == 64)
            temp = ascii_6432[num][i]; /* 调用32x64字体 */
        else
        {
            /* 不支持的字号，显示默认字符 */
            temp = ascii_1608[num][i]; /* 使用16号字体作为默认 */
        }
        for (t = 0; t < 8; t++)
        {
            if (!mode) /* 非叠加模式 */
            {
                if (temp & (0x01 << t))
                    LCD_WR_DATA(fc);
                else
                    LCD_WR_DATA(bc);
                m++;
                if (m % sizex == 0)
                {
                    m = 0;
                    break;
                }
            }
            else /* 叠加模式 */
            {
                if (temp & (0x01 << t))
                    LCD_DrawPoint(x, y, fc); /* 在指定位置绘制一个点 */
                x++;
                if ((x - x0) == sizex)
                {
                    x = x0;
                    y++;
                    break;
                }
            }
        }
    }
}

/**
 * @brief 显示字符串
 * @param x 起始显示点x坐标(0~LCD_W)
 * @param y 起始显示点y坐标(0~LCD_H)
 * @param p 要显示的字符串指针（支持ASCII和中文混合）
 * @param fc 字符串的16位RGB前景色
 * @param bc 字符串的16位RGB背景色
 * @param sizey 字号大小(可选12/16/24/32/64像素)
 * @param mode 显示模式(0:非叠加模式，1:叠加模式)
 * @return 无
 * @details 在指定位置显示中英文混合字符串，支持UTF8和GB2312字符集，支持多种字号大小
 */
void LCD_ShowString(uint16_t x, uint16_t y, const uint8_t *p, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint16_t x0 = x;                        /* 保存初始X坐标，用于计算字符间距 */
    uint8_t CharLength = 0;                 /* 当前字符的字节长度 */
    char SingleChar[5];                     /* 存储单个字符的缓冲区 */
    
    while (*p != '\0')                      /* 遍历字符串，直到遇到结束符 */
    {
#ifdef LCD_CHARSET_UTF8     /* 定义字符集为UTF8 */
        /* 此段代码的目的是，提取UTF8字符串中的一个字符，转存到SingleChar子字符串中 */
        /* 判断UTF8编码第一个字节的标志位 */
        if ((*p & 0x80) == 0x00)            /* 第一个字节为0xxxxxxx，ASCII字符 */
        {
            CharLength = 1;                 /* 字符为1字节 */
            SingleChar[0] = *p ++;          /* 将第一个字节写入SingleChar第0个位置，随后p指向下一个字节 */
            SingleChar[1] = '\0';           /* 为SingleChar添加字符串结束标志位 */
        }
        else if ((*p & 0xE0) == 0xC0)       /* 第一个字节为110xxxxx，2字节UTF8字符 */
        {
            CharLength = 2;                 /* 字符为2字节 */
            SingleChar[0] = *p ++;          /* 将第一个字节写入SingleChar第0个位置，随后p指向下一个字节 */
            if (*p == '\0') {break;}        /* 意外情况，跳出循环，结束显示 */
            SingleChar[1] = *p ++;          /* 将第二个字节写入SingleChar第1个位置，随后p指向下一个字节 */
            SingleChar[2] = '\0';           /* 为SingleChar添加字符串结束标志位 */
        }
        else if ((*p & 0xF0) == 0xE0)       /* 第一个字节为1110xxxx，3字节UTF8字符 */
        {
            CharLength = 3;                 /* 字符为3字节 */
            SingleChar[0] = *p ++;          /* 读取第一个字节 */
            if (*p == '\0') {break;}        /* 检查字符串是否意外结束 */
            SingleChar[1] = *p ++;          /* 读取第二个字节 */
            if (*p == '\0') {break;}        /* 检查字符串是否意外结束 */
            SingleChar[2] = *p ++;          /* 读取第三个字节 */
            SingleChar[3] = '\0';           /* 为SingleChar添加字符串结束标志位 */
        }
        else if ((*p & 0xF8) == 0xF0)       /* 第一个字节为11110xxx，4字节UTF8字符 */
        {
            CharLength = 4;                 /* 字符为4字节 */
            SingleChar[0] = *p ++;          /* 读取第一个字节 */
            if (*p == '\0') {break;}        /* 检查字符串是否意外结束 */
            SingleChar[1] = *p ++;          /* 读取第二个字节 */
            if (*p == '\0') {break;}        /* 检查字符串是否意外结束 */
            SingleChar[2] = *p ++;          /* 读取第三个字节 */
            if (*p == '\0') {break;}        /* 检查字符串是否意外结束 */
            SingleChar[3] = *p ++;          /* 读取第四个字节 */
            SingleChar[4] = '\0';           /* 为SingleChar添加字符串结束标志位 */
        }
        else
        {
            /* 编码解析失败，可能是GB2312字符被当作UTF-8解析 */
            /* 尝试按GB2312格式处理：如果是中文字符（最高位为1），跳过2字节 */
            if ((*p & 0x80) != 0x00)    /* 最高位为1，可能是GB2312中文字符 */
            {
                LCD_ShowChar(x0, y, '?', fc, bc, sizey, mode);
                x0 += sizey;            /* 按中文字符宽度处理 */
                p ++;                   /* 跳过第一个字节 */
                if (*p != '\0' && (*p & 0x80) != 0x00) /* 如果第二个字节也是中文字节 */
                {
                    p ++;               /* 跳过第二个字节 */
                }
            }
            else                        /* ASCII字符解析失败 */
            {
                LCD_ShowChar(x0, y, '?', fc, bc, sizey, mode);
                x0 += sizey / 2;        /* 按ASCII字符宽度处理 */
                p ++;                   /* 跳过当前字节 */
            }
            continue;
        }
#endif
        
    #ifdef LCD_CHARSET_GB2312   /* 定义字符集为GB2312 */
        /* 此段代码的目的是，提取GB2312字符串中的一个字符，转存到SingleChar子字符串中 */
        /* 判断GB2312字节的最高位标志位 */
        if ((*p & 0x80) == 0x00)            /* 最高位为0，ASCII字符 */
        {
            CharLength = 1;                 /* 字符为1字节 */
            SingleChar[0] = *p ++;          /* 将第一个字节写入SingleChar第0个位置，随后p指向下一个字节 */
            SingleChar[1] = '\0';           /* 为SingleChar添加字符串结束标志位 */
        }
        else                                /* 最高位为1，GB2312中文字符 */
        {
            CharLength = 2;                 /* 字符为2字节 */
            SingleChar[0] = *p ++;          /* 将第一个字节写入SingleChar第0个位置，随后p指向下一个字节 */
            if (*p == '\0') {break;}        /* 意外情况，跳出循环，结束显示 */
            SingleChar[1] = *p ++;          /* 将第二个字节写入SingleChar第1个位置，随后p指向下一个字节 */
            SingleChar[2] = '\0';           /* 为SingleChar添加字符串结束标志位 */
        }
    #endif
        
        /* 显示上述代码提取到的SingleChar */
        if (CharLength == 1)                /* 如果是单字节字符（ASCII字符） */
        {
            /* 使用LCD_ShowChar显示此ASCII字符 */
            LCD_ShowChar(x0, y, SingleChar[0], fc, bc, sizey, mode);
            x0 += sizey / 2;                /* ASCII字符宽度为字号的一半，更新下一个字符的X坐标 */
        }
        else                                /* 否则，即多字节字符（中文字符） */
        {
            /* 调用LCD_ShowChinese显示中文字符 */
            LCD_ShowChinese(x0, y, (uint8_t *)SingleChar, fc, bc, sizey, mode);
            x0 += sizey;                    /* 中文字符宽度等于字号，更新下一个字符的X坐标 */
        }
    }
}

/**
 * @brief LCD格式化打印函数（支持中英文混合）
 * @param x 显示位置x坐标(0~LCD_W)
 * @param y 显示位置y坐标(0~LCD_H)
 * @param fc 字符串的16位RGB前景色
 * @param bc 字符串的16位RGB背景色
 * @param sizey 字号大小(可选12/16/24/32/64像素)
 * @param mode 显示模式(0:非叠加模式，1:叠加模式)
 * @param format 格式化字符串（支持ASCII和中文混合）
 * @param ... 可变参数列表
 * @return 无
 * @details 在指定位置显示格式化的中英文混合字符串，支持UTF8和GB2312字符集
 */
void LCD_Printf(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode, char *format, ...)
{
    char String[256];                    /* 定义字符数组 */
    va_list arg;                        /* 定义可变参数列表数据类型的变量arg */
    va_start(arg, format);              /* 从format开始，接收参数列表到arg变量 */
    vsprintf(String, format, arg);      /* 使用vsprintf打印格式化字符串和参数列表到字符数组中 */
    va_end(arg);                        /* 结束变量arg */
    LCD_ShowString(x, y, (const uint8_t *)String, fc, bc, sizey, mode); /* LCD显示字符数组（字符串） */
}

/* -------------------------------------------- 字符串宽度计算函数 -------------------------------------------- */

/**
 * @brief 计算字符串的显示宽度（像素）
 * @param p 要计算的字符串指针（支持ASCII和中文混合）
 * @param sizey 字号大小(可选12/16/24/32/64像素)
 * @return uint16_t 字符串的显示宽度（像素）
 * @details 根据字符编码正确计算字符串的实际显示宽度，支持UTF8和GB2312字符集
 */
uint16_t LCD_GetStringDisplayWidth(const uint8_t *p, uint8_t sizey)
{
    uint16_t totalWidth = 0;                /* 总显示宽度 */
    uint8_t CharLength = 0;                 /* 当前字符的字节长度 */
    uint8_t charWidth = sizey / 2;          /* ASCII字符宽度（字号的一半） */
    uint8_t chineseWidth = sizey;           /* 中文字符宽度（等于字号） */
    
    while (*p != '\0')                      /* 遍历字符串，直到遇到结束符 */
    {
#ifdef LCD_CHARSET_UTF8     /* 定义字符集为UTF8 */
        /* 判断UTF8编码第一个字节的标志位 */
        if ((*p & 0x80) == 0x00)            /* 第一个字节为0xxxxxxx，ASCII字符 */
        {
            CharLength = 1;                 /* 字符为1字节 */
            totalWidth += charWidth;        /* ASCII字符宽度 */
            p += CharLength;                /* 指向下一个字符 */
        }
        else if ((*p & 0xE0) == 0xC0)       /* 第一个字节为110xxxxx，2字节UTF8字符 */
        {
            CharLength = 2;                 /* 字符为2字节 */
            totalWidth += chineseWidth;     /* 中文字符宽度 */
            p += CharLength;                /* 指向下一个字符 */
        }
        else if ((*p & 0xF0) == 0xE0)       /* 第一个字节为1110xxxx，3字节UTF8字符 */
        {
            CharLength = 3;                 /* 字符为3字节 */
            totalWidth += chineseWidth;     /* 中文字符宽度 */
            p += CharLength;                /* 指向下一个字符 */
        }
        else if ((*p & 0xF8) == 0xF0)       /* 第一个字节为11110xxx，4字节UTF8字符 */
        {
            CharLength = 4;                 /* 字符为4字节 */
            totalWidth += chineseWidth;     /* 中文字符宽度 */
            p += CharLength;                /* 指向下一个字符 */
        }
        else
        {
            p++;                            /* 意外情况，跳过此字节 */
            continue;
        }
#endif
        
#ifdef LCD_CHARSET_GB2312   /* 定义字符集为GB2312 */
        /* 判断GB2312字节的最高位标志位 */
        if ((*p & 0x80) == 0x00)            /* 最高位为0，ASCII字符 */
        {
            CharLength = 1;                 /* 字符为1字节 */
            totalWidth += charWidth;        /* ASCII字符宽度 */
            p += CharLength;                /* 指向下一个字符 */
        }
        else                                /* 最高位为1，GB2312中文字符 */
        {
            CharLength = 2;                 /* 字符为2字节 */
            totalWidth += chineseWidth;     /* 中文字符宽度 */
            p += CharLength;                /* 指向下一个字符 */
        }
#endif
    }
    
    return totalWidth;
}

/* -------------------------------------------- 数值显示函数 -------------------------------------------- */

/**
 * @brief 计算幂函数
 * @param m 底数(0~255)
 * @param n 指数(0~255)
 * @return uint32_t 计算结果m的n次方
 * @details 用于数值显示时的位数计算
 */
uint32_t mypow(uint8_t m, uint8_t n)
{
    uint32_t result = 1;
    while (n--)
        result *= m;
    return result;
}

/**
 * @brief 显示整数变量
 * @param x 数字显示位置x坐标(0~LCD_W)
 * @param y 数字显示位置y坐标(0~LCD_H)
 * @param num 要显示的整数值(0~65535)
 * @param len 要显示的位数(1~5)
 * @param fc 数字的16位RGB前景色
 * @param bc 数字的16位RGB背景色
 * @param sizey 字号大小(可选12/16/24/32像素)
 * @return 无
 * @details 在指定位置显示一个无符号整数，左对齐，不足位数用空格补齐
 */
void LCD_ShowIntNum(uint16_t x, uint16_t y, uint16_t num, uint8_t len, uint16_t fc, uint16_t bc, uint8_t sizey)
{
    uint8_t t, temp;                    /* t:循环计数器，temp:当前位的数字 */
    uint8_t enshow = 0;                 /* 显示标志位，0表示不显示前导零，1表示开始显示数字 */
    uint8_t sizex = sizey / 2;          /* 计算字符宽度，ASCII字符宽度为字号的一半 */
    
    /* 从左到右依次显示每一位数字 */
    for (t = 0; t < len; t++)
    {
        /* 提取当前位的数字：从高位到低位依次提取 */
        /* mypow(10, len - t - 1)计算当前位的权重（如1000、100、10、1） */
        /* num / 权重 得到当前位及更高位的数字 */
        /* % 10 取余数得到当前位的数字（0-9） */
        temp = (num / mypow(10, len - t - 1)) % 10;
        
        /* 处理前导零：如果还没有开始显示有效数字，且不是最后一位，且当前位是0 */
        if (enshow == 0 && t < (len - 1))
        {
            if (temp == 0)
            {
                /* 显示空格代替前导零，实现左对齐效果 */
                LCD_ShowChar(x + t * sizex, y, ' ', fc, bc, sizey, 0);
                continue;                /* 跳过当前循环，继续处理下一位 */
            }
            else
                enshow = 1;             /* 遇到第一个非零数字，开始显示数字 */
        }
        
        /* 显示当前位的数字：temp + 48将数字转换为ASCII字符 */
        /* 48是字符'0'的ASCII码，所以temp + 48就是对应的数字字符 */
        LCD_ShowChar(x + t * sizex, y, temp + 48, fc, bc, sizey, 0);
    }
}

/**
 * @brief 显示两位小数变量
 * @param x x坐标
 * @param y y坐标
 * @param num 要显示的小数变量
 * @param len 要显示的位数
 * @param fc 字的颜色
 * @param bc 字的背景色
 * @param sizey 字号
 * @return 无
 */
void LCD_ShowFloatNum1(uint16_t x, uint16_t y, float num, uint8_t len, uint16_t fc, uint16_t bc, uint8_t sizey)
{
    uint8_t t, temp, sizex;             /* t:循环计数器，temp:当前位的数字，sizex:字符宽度 */
    uint16_t num1;                      /* 将浮点数转换为整数进行处理 */
    sizex = sizey / 2;                  /* 计算字符宽度，ASCII字符宽度为字号的一半 */
    num1 = num * 100;                   /* 将浮点数乘以100，保留两位小数 */
    
    /* 从左到右依次显示每一位数字 */
    for (t = 0; t < len; t++)
    {
        /* 提取当前位的数字：从高位到低位依次提取 */
        /* mypow(10, len - t - 1)计算当前位的权重 */
        /* num1 / 权重 得到当前位及更高位的数字 */
        /* % 10 取余数得到当前位的数字（0-9） */
        temp = (num1 / mypow(10, len - t - 1)) % 10;
        
        /* 在倒数第二位插入小数点（即小数点的位置） */
        if (t == (len - 2))
        {
            /* 显示小数点 */
            LCD_ShowChar(x + (len - 2) * sizex, y, '.', fc, bc, sizey, 0);
            t++;                        /* 跳过当前循环，因为已经显示了小数点 */
            len += 1;                   /* 增加总长度，为小数点腾出空间 */
        }
        
        /* 显示当前位的数字：temp + 48将数字转换为ASCII字符 */
        LCD_ShowChar(x + t * sizex, y, temp + 48, fc, bc, sizey, 0);
    }
}

/* -------------------------------------------- 图片显示和测试函数 -------------------------------------------- */

/**
 * @brief 显示图片
 * @param x x坐标
 * @param y y坐标
 * @param length 图片长度
 * @param width 图片宽度
 * @param pic[] 图片数组
 * @return 无
 */
void LCD_ShowPicture(uint16_t x, uint16_t y, uint16_t length, uint16_t width, const uint8_t pic[])
{
    uint16_t i, j;                      /* i:行计数器，j:列计数器 */
    uint32_t k = 0;                     /* k:图片数组的索引计数器 */
    
    /* 设置LCD显示区域：从(x,y)到(x+length-1,y+width-1) */
    /* 这样LCD就知道要在这个矩形区域内显示图片数据 */
    LCD_Address_Set(x, y, x + length - 1, y + width - 1);
    
    /* 逐行扫描图片 */
    for (i = 0; i < length; i++)
    {
        /* 逐列扫描图片 */
        for (j = 0; j < width; j++)
        {
            /* 每个像素占用2个字节（16位RGB565格式） */
            /* pic[k * 2]是当前像素的高8位（红色和绿色高位） */
            /* pic[k * 2 + 1]是当前像素的低8位（绿色低位和蓝色） */
            LCD_WR_DATA8(pic[k * 2]);       /* 写入高8位数据 */
            LCD_WR_DATA8(pic[k * 2 + 1]);   /* 写入低8位数据 */
            k++;                            /* 移动到下一个像素 */
        }
    }
}

/**
 * @brief 字体大小对比测试函数
 * @details 在同一屏幕上显示16、32、64像素的英文字母和数字，便于对比
 */
void LCD_FontAllSizeTest(void)
{
    uint16_t y = 0;
    /* 清屏 */
    LCD_Fill(0, 0, LCD_W, LCD_H, WHITE);

    /* 16像素字体（前两行） */
    LCD_ShowString(0, y, (const uint8_t *)"16px: ABCDEFGHIJKLMN", BLACK, WHITE, 16, 0);
    y += 16;
    LCD_ShowString(0, y, (const uint8_t *)"16px: 0123456789", BLUE, WHITE, 16, 0);
    y += 20;

    /* 32像素字体（中间两行） */
    LCD_ShowString(0, y, (const uint8_t *)"32px: ABCDEFG", RED, WHITE, 32, 0);
    y += 32;
    LCD_ShowString(0, y, (const uint8_t *)"32px: 0123456", GREEN, WHITE, 32, 0);
    y += 36;

    /* 64像素字体（底部两行） */
    LCD_ShowString(0, y, (const uint8_t *)"64px: AB", BLACK, WHITE, 64, 0);
    y += 64;
    LCD_ShowString(0, y, (const uint8_t *)"64px: 12", BLUE, WHITE, 64, 0);
}
